package com.moro.lisp.tools;

import java.util.ArrayList;
import java.util.List;

import com.moro.lisp.JLispData;
import com.moro.lisp.JLispType;
import com.moro.lisp.closure.Action;
import com.moro.lisp.closure.ActionStatus;
import com.moro.lisp.os.Terminal;
import com.moro.lisp.typedefine.Function;
import com.moro.lisp.typedefine.Atom;
import com.moro.lisp.typedefine.Error;

/**
 * 这是专属于JavaLisp的自定义栈类型，除实现了通用的栈类型功能外，
 * 额外提供支持Lisp中变量捕获，变量标记等功能
 * @author HJ
 *
 */

public class JLispStack {//自定义栈类型
	/*
	 * 该值栈所归属的原子
	 */
	public Atom atom;
	/*
	 * 这个字段表示用来存储JavaLisp数据的list集合
	 */
	private List<JLispData> values;
	
	
	
	/*
	 * 这个字段用来表示一个值栈对各个函数的绑定（主要在闭包中体现）
	 * 当给一个符号的函数值重新赋值函数的时候，要重新刷新此绑定（如果该函数不再是任何符号的函数值或一般值，则移除该函数
	 * 如果一个变量的绑定函数个数为0，则移除此变量）
	 */
	private List<Action> bindings;
	
	
	
	/*
	 * 这个字段用来表示当前集合中值的个数，（注意是当前实时的个数，不能小于0）
	 */
	private int size;
	
	
	
	/*
	 * 一个空参数的构造方法
	 */
	public JLispStack(Atom atom) {
		this.atom = atom;
		this.values = new ArrayList<JLispData>();
		this.bindings = new ArrayList<Action>();
		this.size = this.values.size();
	}
	
	/*
	 * 压栈，每声明并赋值一个新的变量都要进行压栈操作
	 */
	public void push(JLispData value) {
		this.values.add(value);
		
		
		this.size = this.values.size();
		
		/*
		 * 每一次入栈，如果该符号中有Action状态为nowaction的action需要改变状态为inaction
		 */
		for(Action action:this.bindings) {
			if(ActionStatus.NOWACTION == action.status) {
				action.status = ActionStatus.INACTION;
				break;
			}
		}
	}
	
	
	/*
	 * 给当前栈顶的变量重新赋值
	 */
	public void resetVal(JLispData value) {
		this.values.set(this.size - 1, value);
		for(Action action:this.bindings) {
			if(ActionStatus.NOWACTION == action.status) {
				action.value = value;
				break;
			}
		}
	}
	
	public void resetValById(JLispData val, int id) {//重设指定值栈中指定索引值的值，此情况一般发生在执行闭包的时候，如果对应的action状态不为alone的话
											//除了要将对应action的值改变，同时还要将符号值栈中与action索引值相同的值重设，这种现象叫闭包的实时执行，
		if(val.type == JLispType.MACRO) {//如果值是Macro则直接返回不作任何操作
			new Error("The macro can not be symbol's general value");
			return;
		}
		if(null != this.now()) {
			if(this.now().type == JLispType.FUNCTION) {
				((Function)(this.now().data)).asSymbolValue.remove(this.atom);
			}else if(val.type == JLispType.FUNCTION) {
				((Function)(val.data)).asSymbolValue.add(this.atom);
			}
		}
		this.values.set(id, val);
	}
	public JLispData getValById(int id) {
		return this.values.get(id);
	}
	
	/*
	 * 出栈，每离开一个变量的作用域都要进行出栈操作
	 */
	public void pop() {
		
		this.values.remove(--this.size);
		/*
		 * 每一次出栈，如果符号的所有Action中状态为nowaction的action需要改变状态为alone
		 * 然后检查所有状态为inaction的action，如果有action索引值为出栈之后的当前索引值，则将这个action状态设为nowaction
		 */
		for(Action action:this.bindings) {
			if(ActionStatus.NOWACTION == action.status) {
				action.status = ActionStatus.ALONE;
				break;
			}
		}
		for(Action action:this.bindings) {
			if(ActionStatus.INACTION == action.status && this.size - 1 == action.indexOfSymbolValue) {
				action.status = ActionStatus.NOWACTION;
				break;
			}
		}
		
	}
	
	
	
	/*
	 * 读取符号在当前作用域的值
	 */
	public JLispData now() {
		if(0 == this.size) {
			return null;
		}
		return this.values.get(this.size - 1);
	}
	
	
	
	/*
	 * 函数捕获（绑定）变量操作，只发生在函数定义操作的时候
	 */
	public Action bind(JLispData fun) {//将该值栈的对应层绑定一个函数或宏
		/*
		 * 将当前值绑定一个函数时所发生的逻辑如下
		 * 1，遍历所有ACTION，找到状态为NOWACTION的ACTION,将该函数添加进去
		 * 如果没有活跃的ACTION则添加ACTION
		 */
		for(Action action:this.bindings) {
			if(ActionStatus.NOWACTION == action.status) {
				action.addFunctionOrMacro(fun);
				return action;
			}
		}
		if(this.size == 0) {//如果当前值栈中值的个数为0，（这种情况下发生在顶层定义函数时），则自动给该原子的值栈添加一个null值
			this.push(null);
		}
		Action action = new Action(this, this.now(),this.size - 1);
		action.addFunctionOrMacro(fun);
		this.bindings.add(action);
		return action;
		
	}
	public void rBind(JLispData fun) {
		for(Action action:this.bindings) {
			if(action.removeFunctionOrMacro(fun)) {
				break;
			}
		}
		for(int i = 0;i < this.bindings.size();i++) {
			if(this.bindings.get(i).bindingFunctionOrMacro.size() == 0) {
				this.bindings.remove(i--);
			}
		}
	}
	
	public int getSize() {
		return this.size;
	}
	
}
